<template>
  <div>
    <div
      v-if="isOpen && isMask"
      :class="{ 'mask-fade-in': isOpen, 'mask-fade-out': !isOpen && isMounted }"
      class="drawer-mask"
      @click="close"
    ></div>
    <div
      v-if="isOpen || isAnimating"
      :class="{
        'drawer-slide-in': isOpen,
        'drawer-slide-out': !isOpen && isMounted,
        [`drawer-${position}`]: true
      }"
      :style="[drawerStyle, drawerRadiusStyle]"
      class="drawer-content hide-scrollbar"
    >
      <!--   头部   -->
      <div v-if="isHeader" class="header">
        <slot name="header">
          <div class="drawer-header">
            <i class="iconfont icon-guanbi" @click="close"></i>
          </div>
        </slot>
      </div>
      <slot></slot>
    </div>
  </div>
</template>

<script setup>
import { ref, watch, onMounted, computed } from 'vue'

const props = defineProps({
  position: {
    type: String,
    default: 'right',
    validator: (val) => ['left', 'right', 'top', 'bottom'].includes(val)
  },
  isHeader: {
    type: Boolean,
    default: false
  },
  width: {
    type: Number,
    default: 300
  },
  height: {
    type: Number,
    default: 300
  },
  isMask: {
    type: Boolean,
    default: true
  },
  margin: {
    type: Number,
    default: 0
  },
  radius: {
    type: Number,
    default: 0
  }
})

const emit = defineEmits(['open', 'close'])

const isOpen = ref(false)
const isAnimating = ref(false)
const isMounted = ref(false)

let animationTimeout

onMounted(() => {
  isMounted.value = true
})

const drawerStyle = computed(() => {
  if (['left', 'right'].includes(props.position)) {
    return {
      width: `${props.width}px`,
      margin: `${props.margin}px 0`
    }
  } else {
    return {
      height: `${props.height}px`,
      margin: `0 ${props.margin}px`
    }
  }
})
const drawerRadiusStyle = computed(() => {
  if (props.position === 'right') {
    return {
      borderRadius: `${props.radius}px 0 0 ${props.radius}px`
    }
  } else if (props.position === 'top') {
    return {
      borderRadius: `${props.radius}px ${props.radius}px 0 0`
    }
  } else if (props.position === 'bottom') {
    return {
      borderRadius: `0 0 ${props.radius}px ${props.radius}px`
    }
  } else {
    return {
      borderRadius: `0 ${props.radius}px ${props.radius}px 0`
    }
  }
})

const open = () => {
  isOpen.value = true
  isAnimating.value = true
  emit('open')
  clearTimeout(animationTimeout)
}

const close = () => {
  isOpen.value = false
  emit('close')
  animationTimeout = setTimeout(() => {
    isAnimating.value = false
  }, 300)
}

watch(isOpen, (newVal) => {
  if (newVal) {
    document.body.style.overflow = 'hidden'
  } else {
    document.body.style.overflow = ''
  }
})

defineExpose({
  open,
  close
})
</script>

<style scoped>
.header {
  position: sticky;
  top: 0;
  background-color: var(--inputBg);
}

.drawer-mask {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  z-index: 999;
  opacity: 0;
}

.drawer-content {
  position: fixed;
  background: var(--inputBg);
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  z-index: 1000;
  overflow: auto;
}

.drawer-header {
  padding: 10px 20px;
  text-align: right;
}

.drawer-header span {
  cursor: pointer;
  font-size: 30px;
  transition: all 0.3s;
}

.drawer-header span:hover {
  transform: rotate(180deg);
}

/* 位置样式 */
.drawer-left {
  top: 0;
  left: 0;
  bottom: 0;
  transform: translateX(-100%);
}

.drawer-right {
  top: 0;
  right: 0;
  bottom: 0;
  transform: translateX(100%);
}

.drawer-top {
  top: 0;
  left: 0;
  right: 0;
  transform: translateY(-100%);
}

.drawer-bottom {
  bottom: 0;
  left: 0;
  right: 0;
  transform: translateY(100%);
}

/* 遮罩层动画 */
.mask-fade-in {
  animation: maskFadeIn 0.3s ease forwards;
}

.mask-fade-out {
  animation: maskFadeOut 0.3s ease forwards;
}

@keyframes maskFadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes maskFadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

/* 抽屉内容动画 */
.drawer-slide-in {
  animation: drawerSlideIn 0.3s cubic-bezier(0.33, 1, 0.68, 1) forwards;
}

.drawer-slide-out {
  animation: drawerSlideOut 0.3s cubic-bezier(0.32, 0, 0.67, 0) forwards;
}

/* 水平方向动画 */
.drawer-left.drawer-slide-in {
  animation-name: drawerSlideInLeft;
}

.drawer-left.drawer-slide-out {
  animation-name: drawerSlideOutLeft;
}

.drawer-right.drawer-slide-in {
  animation-name: drawerSlideInRight;
}

.drawer-right.drawer-slide-out {
  animation-name: drawerSlideOutRight;
}

/* 垂直方向动画 */
.drawer-top.drawer-slide-in {
  animation-name: drawerSlideInTop;
}

.drawer-top.drawer-slide-out {
  animation-name: drawerSlideOutTop;
}

.drawer-bottom.drawer-slide-in {
  animation-name: drawerSlideInBottom;
}

.drawer-bottom.drawer-slide-out {
  animation-name: drawerSlideOutBottom;
}

/* 动画定义 */
@keyframes drawerSlideInLeft {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0);
  }
}

@keyframes drawerSlideOutLeft {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-100%);
  }
}

@keyframes drawerSlideInRight {
  from {
    transform: translateX(100%);
  }
  to {
    transform: translateX(0);
  }
}

@keyframes drawerSlideOutRight {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(100%);
  }
}

@keyframes drawerSlideInTop {
  from {
    transform: translateY(-100%);
  }
  to {
    transform: translateY(0);
  }
}

@keyframes drawerSlideOutTop {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(-100%);
  }
}

@keyframes drawerSlideInBottom {
  from {
    transform: translateY(100%);
  }
  to {
    transform: translateY(0);
  }
}

@keyframes drawerSlideOutBottom {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(100%);
  }
}
</style>
